package com.barkerton.crawler.util;

import java.io.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * General utility class for file IO.
 * 
 * @author c.barker
 *
 */
public class Util {

	private static Log log = LogFactory.getLog(Util.class);
	
	/**
	 * Returns content from text file.
	 * @param f	Absolute path of file
	 * @return	Text contained in file
	 */
	public static String readFile(String f) {
		return readFile(new File(f));
	}
	
	/**
	 * Returns content from text file.
	 * @param f	File to read
	 * @return	Text contained in file
	 */
	public static String readFile(File f) {
		StringBuffer content = new StringBuffer();
		
		try {
			BufferedReader in = new BufferedReader(new FileReader(f));
		    String str;
		    while ((str = in.readLine()) != null) {
		    	content.append(str+"\n");
		    }
		    in.close();
		} 
		catch (IOException ioe) {
			log.error("Unable to read file ["+f.getAbsolutePath()+"] " + ioe.getMessage());
		}
		
		return content.toString();
	}
	
	/**
	 * Create/write the content to file.
	 * @param f			File to write to
	 * @param content	Content to write
	 * @return			Boolean denoting if IO was successful or not
	 */
	public static boolean writeFile(File f, String content) {
		try {
	        BufferedWriter out = new BufferedWriter(new FileWriter(f));
	        out.write(content);
	        out.close();
	    } 
		catch (IOException ioe) {
	    	log.error("Unable to write file ["+f.getAbsolutePath()+"] " + ioe.getMessage());
	    	return false;
	    }
	    
	    return true;
	}
	
	/**
	 * Serializes the object to a byte array and writes it to a file.
	 * @param f		File to write serialize object to
	 * @param obj	Object to serialize
	 * @return		Boolean denoting whether or not the operation was successful
	 */
	public static boolean serialize(File f, Object obj) {		
	    try {
	        // Serialize to a file
	        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(f));
	        out.writeObject(obj);
	        out.close();
	    
	        // Serialize to a byte array
	        ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
	        out = new ObjectOutputStream(bos) ;
	        out.writeObject(obj);
	        out.close();
	    } 
	    catch (IOException ioe) {
	    	log.error("Unable to serialize to file [" + f.getAbsolutePath() + "] " + ioe.getMessage());
			return false;
	    }
	    
	    return true;
	}
	
	/**
	 * Deserializes a file from a byte array.
	 * @param f		File to deserialize bytes from
	 * @return		Object deserialized
	 */
	public static Object deserialize(File f) {
		Object obj = null;
		try {
	        // Get some byte array data
	        byte[] bytes = getBytesFromFile(f);
	   
	        // Deserialize from a byte array
	        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
	        obj = in.readObject();
	        in.close();
	    } 
		catch (ClassNotFoundException cnfe) {
			log.error(cnfe.getLocalizedMessage());
	    } 
		catch (IOException ioe) {
			log.error(ioe.getLocalizedMessage());
	    }
	    
	    return obj;
	}
	
	/**
	 * Returns the contents of the file in a byte array.
	 * @param f		File to get bytes from
	 * @return		Array of bytes 
	 * @exception	IOException
	 */
    public static byte[] getBytesFromFile(File file) throws IOException {
        InputStream is = new FileInputStream(file);
    
        long length = file.length();
    
        // You cannot create an array using a long type.
        // It needs to be an int type.
        // Before converting to an int type, check
        // to ensure that file is not larger than Integer.MAX_VALUE.
        if (length > Integer.MAX_VALUE) {
        	log.error("Unable to get bytes from file ["+ file.getAbsolutePath() + "] it is too long.");
        	return null;
        }
    
        // Create the byte array to hold the data
        byte[] bytes = new byte[(int)length];
    
        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
               && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
            offset += numRead;
        }
    
        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file "+file.getName());
        }
    
        // Close the input stream and return bytes
        is.close();
        return bytes;
    }
}
